# coding = utf-8
import datetime
import json

import logging
import os
import random
import time
from io import BytesIO
from urllib.parse import urlparse, urlunparse

from PIL import Image
from django.db.models import Q, F, Sum
from django.http import HttpResponse

from wechatpy import WeChatPayException
from wechatpy.exceptions import InvalidSignatureException
from wechatpy.pay import dict_to_xml

from member.models import BonusPoint
from wine import settings
from rest_framework import mixins, status
from rest_framework.decorators import action
from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework.viewsets import ReadOnlyModelViewSet, GenericViewSet, ModelViewSet

from wxchat.api.permissions import WeixinPermission
from wxchat.api.serializers import SwipeImageSerializer, UserRoleSerializer, WxUserInfoSerializer, \
    RechargeListSerializer, RechargeRecordSerializer, WxPayResultSerializer, WxUnifiedOrderResultSerializer
from wxchat.api.utils import md5_encrypt, get_openid_from_header, WeixinPay, get_user_by_openid
from wxchat.models import SwipeImage, WxUserInfo, RechargeList, RechargeRecord, WxUnifiedOrderResult, WxPayResult
from wxchat.utils import create_qrcode, mergeRightImage, mergeImage
from wxchat.views import wxClient


logger = logging.getLogger("django")


class QrCodeAPIView(APIView):
    """二维码"""
    authentication_classes = ()

    def get(self, request, *args, **kwargs):
        direct_url = request.query_params.get("url")

        ps = urlparse(direct_url)

        fragment = ps.fragment

        key = md5_encrypt(str(time.time()))
        if '?' in fragment:
            fragment = f'{fragment}&key={key}'
        else:
            fragment = f'{fragment}?key={key}'

        ps_list = list(ps)

        ps_list[-1] = fragment

        new_url = urlunparse(ps_list)
        print(new_url)
        f = BytesIO()
        if direct_url:
            image = create_qrcode(new_url, fill_color="green", back_color="white")
            image.save(f, "PNG")

        return HttpResponse(f.getvalue(), content_type="image/png")


class QrCodeWithLogoAPIView(APIView):
    """二维码带Logo"""
    authentication_classes = ()

    def get(self, request, *args, **kwargs):
        direct_url = request.query_params.get("url")
        f = BytesIO()
        if direct_url:
            image = create_qrcode(direct_url)
            logo = Image.open(os.path.join(settings.STATIC_ROOT, 'images/logo.jpg'))
            image = mergeImage(image, logo)
            image.save(f, "PNG")

        return HttpResponse(f.getvalue(), content_type="image/png")


class QrCodeWithBgAPIView(APIView):
    """二维码"""
    authentication_classes = ()

    def get(self, request, *args, **kwargs):
        direct_url = request.query_params.get("url")
        code = request.query_params.get("code")
        f = BytesIO()
        if direct_url:
            image = create_qrcode(direct_url)
            bg_image_path = ''
            if code == "consult":
                bg_image_path = os.path.join(settings.STATIC_ROOT, r'images/card-bg.png')
            elif code == "advisor":
                bg_image_path = os.path.join(settings.STATIC_ROOT, r'images/advisor.png')
            elif code == "lawyer":
                bg_image_path = os.path.join(settings.STATIC_ROOT, r'images/lawyer.png')
            elif code == "rights":
                bg_image_path = os.path.join(settings.STATIC_ROOT, r'images/rights.png')

            bg = Image.open(bg_image_path)
            image = mergeRightImage(bg, image)
            image.save(f, "PNG")
        return HttpResponse(f.getvalue(), content_type="image/png")


class SwipeImageViewSet(ReadOnlyModelViewSet):
    """图片轮播"""
    authentication_classes = ()
    permission_classes = ()
    pagination_class = None
    queryset = SwipeImage.objects.filter(is_show=True)
    serializer_class = SwipeImageSerializer


class UserRoleViewSet(mixins.RetrieveModelMixin,
                      mixins.UpdateModelMixin,
                      GenericViewSet):
    authentication_classes = ()
    permission_classes = ()
    pagination_class = None
    queryset = WxUserInfo.objects.all()
    serializer_class = UserRoleSerializer
    lookup_field = 'openid'
    lookup_url_kwarg = 'openid'


class WxUserInfoViewSet(ModelViewSet):
    """用户信息(公众号号)"""
    # authentication_classes = ()
    permission_classes = ()
    queryset = WxUserInfo.objects.all()
    serializer_class = WxUserInfoSerializer

    def get_queryset(self):
        queryset = super().get_queryset()
        name = self.request.query_params.get("name", None)

        staff = self.request.query_params.get("staff", None)

        birthday = self.request.query_params.get("birthday", None)

        if staff:
            queryset = queryset.filter(staff=int(staff))

        if name:
            queryset = queryset.filter(Q(name__contains=name) | Q(openid__contains=name) | Q(nickname__contains=name) | Q(telephone__contains=name))

        if birthday:
            birth_date = datetime.datetime.strptime(birthday, '%Y-%m-%d')
            print(type(birth_date), birth_date.month, birth_date.day)
            queryset = queryset.filter(birthday__month=birth_date.month, birthday__day=birth_date.day)
            print(queryset.query)

        return queryset

    @action(methods=['delete'], detail=False)
    def batch_delete(self, request, *args, **kwargs):
        select_ids = request.data.get("select_ids", None)
        if not select_ids:
            msg = {"status_code": status.HTTP_404_NOT_FOUND, "message": "删除失败!"}
            return Response(data=msg, status=status.HTTP_404_NOT_FOUND)

        self.serializer_class.Meta.model.objects.filter(id__in=select_ids).delete()
        msg = {"status_code": status.HTTP_204_NO_CONTENT, "message": "删除成功!"}
        return Response(data=msg, status=status.HTTP_204_NO_CONTENT)


class WxMenuAPIView(APIView):
    # authentication_classes = ()
    permission_classes = ()

    def get(self, request, *args, **kwargs):
        res = self.get_menu()
        return Response(res)

    def post(self, request, *args, **kwargs):
        flag = request.data.get("flag", None)

        res = None
        if flag == "create":
            res = self.create_menu()
        elif flag == "delete":
            res = self.delete_menu()
        print(res)
        return Response(res)

    def create_menu(self):
        client = wxClient()
        resp = client.menu.create({
            "button": [
                {
                    "type": "view",
                    "name": "惠生活礼品",
                    "url": settings.ROOT_URL + "/"
                },
                # {
                #     "type": "view",
                #     "name": "我的案件",
                #     "url": settings.ROOT_URL + "/#mycase"
                # },

            ]
        })
        return resp

    def delete_menu(self):
        client = wxClient()
        resp = client.menu.delete()
        return resp

    def get_menu(self):
        client = wxClient()
        resp = client.menu.get()
        return resp


class WxSwipeImageViewSet(ModelViewSet):
    """图片轮播维护"""
    authentication_classes = ()
    permission_classes = ()
    pagination_class = None
    queryset = SwipeImage.objects.all()
    serializer_class = SwipeImageSerializer


class SwipeImageUploadAPIView(APIView):

    def post(self, request, *args, **kwargs):
        # 接收文件
        sid = request.data.get("id", None)
        image = request.FILES.get('image', None)
        name = request.data.get("name", "")
        path = request.data.get("path", "")
        sort = request.data.get("sort", 0)
        is_show = request.data.get("is_show", None)
        print(sid, type(sid), path, sort, is_show)
        if image:
            upload_path = SwipeImage.image.field.upload_to
            dirs = os.path.join(settings.MEDIA_ROOT, upload_path)
            if not os.path.exists(dirs):
                os.makedirs(dirs)

            file_info = image.name.split(".")
            old_file_name = file_info[0]
            file_suffix = file_info[1]
            file_name = '{0}_{1}.{2}'.format(old_file_name, int(time.time()), file_suffix)
            file_path = os.path.join(dirs, file_name)

            with open(file_path, 'wb') as f:
                for chunk in image.chunks():
                    f.write(chunk)

            file_url = '{0}{1}'.format(upload_path, file_name)
            data = {
                'name': name,
                'path': path,
                'image': file_url,
                'sort': int(sort),
                'is_show': 1 if is_show == "true" else 0,
            }

            if sid:
                SwipeImage.objects.filter(id=int(sid)).update(**data)
                obj = SwipeImage.objects.filter(id=int(sid)).first()
            else:
                obj = SwipeImage.objects.create(**data)

            dict_obj = {
                "id": obj.id,
                "name": obj.name,
                "path": obj.path,
                "sort": obj.sort,
                "is_show": obj.is_show,
                "image": "{}://{}{}".format(request.scheme, request.get_host(), obj.image.url),
            }

            msg = {
                "status_code": status.HTTP_200_OK,
                "image": dict_obj,
            }
            return Response(msg)

        return Response({"status_code": status.HTTP_401_UNAUTHORIZED, "message": "上传失败!"})


class RechargeListViewSet(ModelViewSet):
    """充值列表"""
    # authentication_classes = ()
    permission_classes = ()
    pagination_class = None
    queryset = RechargeList.objects.all()
    serializer_class = RechargeListSerializer

    @action(methods=['delete'], detail=False)
    def batch_delete(self, request, *args, **kwargs):
        select_ids = request.data.get("select_ids", None)
        if not select_ids:
            msg = {"status_code": status.HTTP_404_NOT_FOUND, "message": "删除失败!"}
            return Response(data=msg, status=status.HTTP_404_NOT_FOUND)

        self.serializer_class.Meta.model.objects.filter(id__in=select_ids).delete()
        msg = {"status_code": status.HTTP_204_NO_CONTENT, "message": "删除成功!"}
        return Response(data=msg, status=status.HTTP_204_NO_CONTENT)


class RechargeRecordViewSet(ReadOnlyModelViewSet):
    """用户充值记录表"""
    # authentication_classes = ()
    permission_classes = ()
    queryset = RechargeRecord.objects.all()
    serializer_class = RechargeRecordSerializer

    def get_queryset(self):
        queryset = super().get_queryset()
        name = self.request.query_params.get("name", None)
        retailer_id = self.request.query_params.get("retailer", None)
        wx_retailer_id = self.request.query_params.get("retailer_id", None)
        out_trade_no = self.request.query_params.get("out_trade_no", None)
        telephone = self.request.query_params.get("telephone", None)
        search_date = self.request.query_params.getlist("search_date[]", None)

        if retailer_id:
            queryset = queryset.filter(retailer_id=int(retailer_id))

        if wx_retailer_id and int(wx_retailer_id) > 0:
            queryset = queryset.filter(retailer_id=int(wx_retailer_id))

        if name:
            queryset = queryset.filter(Q(name__contains=name) | Q(openid__contains=name))

        if out_trade_no:
            queryset = queryset.filter(out_trade_no__contains=out_trade_no)

        if telephone:
            queryset = queryset.filter(telephone=telephone)

        if search_date and len(search_date) == 2:
            queryset = queryset.filter(pay_time__date__range=(search_date[0], search_date[1]))

        return queryset

    @action(methods=['delete'], detail=False)
    def batch_delete(self, request, *args, **kwargs):
        select_ids = request.data.get("select_ids", None)
        if not select_ids:
            msg = {"status_code": status.HTTP_404_NOT_FOUND, "message": "删除失败!"}
            return Response(data=msg, status=status.HTTP_404_NOT_FOUND)

        self.serializer_class.Meta.model.objects.filter(id__in=select_ids).delete()
        msg = {"status_code": status.HTTP_204_NO_CONTENT, "message": "删除成功!"}
        return Response(data=msg, status=status.HTTP_204_NO_CONTENT)


class WxUnifiedOrderResultViewSet(ModelViewSet):
    """微信统一下单结果"""
    permission_classes = ()
    queryset = WxUnifiedOrderResult.objects.all()
    serializer_class = WxUnifiedOrderResultSerializer

    def get_queryset(self):
        queryset = super().get_queryset()

        search_date = self.request.query_params.getlist("search_date[]", None)

        if search_date and len(search_date) == 2:
            queryset = queryset.filter(create_time__date__range=(search_date[0], search_date[1]))

        return queryset

    @action(methods=['delete'], detail=False)
    def batch_delete(self, request, *args, **kwargs):
        select_ids = request.data.get("select_ids", None)
        if not select_ids:
            msg = {"status_code": status.HTTP_404_NOT_FOUND, "message": "删除失败!"}
            return Response(data=msg, status=status.HTTP_404_NOT_FOUND)

        self.serializer_class.Meta.model.objects.filter(id__in=select_ids).delete()
        msg = {"status_code": status.HTTP_204_NO_CONTENT, "message": "删除成功!"}
        return Response(data=msg, status=status.HTTP_204_NO_CONTENT)


class WxPayResultViewSet(ModelViewSet):
    """微信支付结果"""
    # authentication_classes = ()
    permission_classes = ()
    queryset = WxPayResult.objects.all()
    serializer_class = WxPayResultSerializer

    def get_queryset(self):
        queryset = super().get_queryset()

        name = self.request.query_params.get("name", None)
        search_date = self.request.query_params.getlist("search_date[]", None)

        if name:
            queryset = queryset.filter(Q(openid__contains=name) | Q(out_trade_no__contains=name) | Q(transaction_id__contains=name))

        if search_date and len(search_date) == 2:
            queryset = queryset.filter(add_time__date__range=(search_date[0], search_date[1]))

        return queryset

    @action(methods=['delete'], detail=False)
    def batch_delete(self, request, *args, **kwargs):
        select_ids = request.data.get("select_ids", None)
        if not select_ids:
            msg = {"status_code": status.HTTP_404_NOT_FOUND, "message": "删除失败!"}
            return Response(data=msg, status=status.HTTP_404_NOT_FOUND)

        self.serializer_class.Meta.model.objects.filter(id__in=select_ids).delete()
        msg = {"status_code": status.HTTP_204_NO_CONTENT, "message": "删除成功!"}
        return Response(data=msg, status=status.HTTP_204_NO_CONTENT)


class OrderPayView(APIView):
    """
    充值支付
    """
    authentication_classes = ()
    permission_classes = (WeixinPermission, )

    def post(self, request, *args, **kwargs):
        trade_type = 'JSAPI'
        body = '会员积分充值'
        # 获得订单信息
        money = request.data.get('money', None)
        retailer_id = request.data.get('retailer_id', None)
        score = request.data.get('score', None)
        openid = request.data.get('openid', None)

        if retailer_id is None or score is None or openid is None:
            errors = {
                'return_code': "FAIL",
                'return_msg': "非法参数",
            }
            logger.info(errors)
            return Response(errors)

        if money is None or int(money) <= 0:
            errors = {
                'return_code': "FAIL",
                'return_msg': "请输入充值金额",
            }
            logger.info(errors)
            return Response(errors)

        user = get_user_by_openid(openid)

        out_trade_no = '{0}{1}{2}{3}'.format('H', settings.MCH_ID, datetime.datetime.now().strftime('%Y%m%d%H%M%S'), random.randint(10000, 100000))
        order_data = {
            "out_trade_no": out_trade_no,
            "name": user.name or user.nickname,
            "telephone": user.telephone,
            "openid": openid,
            "retailer_id": int(retailer_id),
            "total_fee": int(money),
            "score": int(score),
        }
        logger.info(order_data)
        order = RechargeRecord.objects.create(**order_data)
        if order:
            total_fee = int(order.total_fee * 100)
        else:
            errors = {
                'return_code': "FAIL",
                'return_msg': "订单不存在",
            }
            return HttpResponse(json.dumps(errors))

        try:
            wxPay = WeixinPay()
            # 测试
            if openid == 'oHW6a5zgKdxF7EpXlNzKDMLekVww' or openid == 'oHW6a52TC076s78vJ1d5UYHNvGoU' or openid == 'oHW6a5712ESQQYxejNNYk4b9QUPM':
                total_fee = 1
            print(settings.NOTIFY_URL)
            data = wxPay.order.create(trade_type=trade_type, body=body, total_fee=total_fee, out_trade_no=out_trade_no, notify_url=settings.NOTIFY_URL, user_id=openid)
            prepay_id = data.get('prepay_id', None)
            save_data = dict(data)
            logger.info(save_data)
            # 保存统一订单数据
            WxUnifiedOrderResult.objects.create(**save_data)
            if prepay_id:
                return_data = wxPay.jsapi.get_jsapi_params(prepay_id=prepay_id, jssdk=True)
                return HttpResponse(json.dumps(return_data))

        except WeChatPayException as wxe:
            errors = {
                'return_code': wxe.return_code,
                'result_code': wxe.result_code,
                'return_msg':  wxe.return_msg,
                'errcode':  wxe.errcode,
                'errmsg':   wxe.errmsg
            }
            logger.info(errors)
            RechargeRecord.objects.filter(out_trade_no=out_trade_no).delete()
            return HttpResponse(json.dumps(errors))


class PayNotify(APIView):
    """支付回调"""
    authentication_classes = ()
    permission_classes = ()

    def post(self, request, *args, **kwargs):
        print("*"*50)
        try:
            wxPay = WeixinPay()
            result_data = wxPay.parse_payment_result(request.body)  # 签名验证
            # 保存支付成功返回数据
            res_data = dict(result_data)
            logger.info(res_data)
            WxPayResult.objects.create(**res_data)
            # 查询订单,判断是否正确
            transaction_id = res_data.get('transaction_id', None)
            out_trade_no = res_data.get('out_trade_no', None)
            openid = res_data.get('openid', None)

            ret_bool = self.query_order(transaction_id, out_trade_no)  # 查询订单

            data = {
                'return_code': result_data.get('return_code'),
                'return_msg': result_data.get('return_msg')
            }
            xml = dict_to_xml(data, '')
            if not ret_bool:  # 订单不存在
                return HttpResponse(xml)
            else:
                # 验证金额是否一致
                if 'return_code' in res_data and 'result_code' in res_data and res_data['return_code'] == 'SUCCESS' and  res_data['result_code'] == 'SUCCESS':
                    time_end = res_data['time_end']
                    pay_time = datetime.datetime.strptime(time_end, "%Y%m%d%H%M%S")

                    user = get_user_by_openid(openid)

                    name = ''
                    if user:
                        name = user.name or user.nickname

                    cash_fee = res_data['cash_fee'] / 100

                    coupon_fee_0 = res_data.get('coupon_fee_0', 0) / 100
                    coupon_fee_1 = res_data.get('coupon_fee_1', 0) / 100

                    data = {
                        "openid": openid,
                        "name": name,
                        "total_fee": res_data['total_fee'] / 100,
                        "transaction_id": res_data['transaction_id'],
                        "cash_fee": cash_fee + coupon_fee_0 + coupon_fee_1,
                        "status": 1,  # 支付
                        "pay_time": pay_time,
                    }
                    logger.info(data)
                    obj, created = RechargeRecord.objects.update_or_create(defaults=data, out_trade_no=out_trade_no)

                    retailer = obj.retailer
                    if retailer:
                        if retailer.out_trade_no != out_trade_no:
                            retailer.out_trade_no = out_trade_no
                            retailer.pay_time = pay_time

                            if retailer.score is None:
                                retailer.score = 0

                            retailer.score += obj.score

                            if retailer.money is None:
                                retailer.money = 0

                            retailer.money += obj.cash_fee

                            retailer.save(update_fields=["money", "out_trade_no", "score", "pay_time"])
                            # 处理不可用积分
                            if retailer.score >= 0:
                                b_ret = BonusPoint.objects.filter(retailer_id=retailer.id, unused_score__gt=0).exists()
                                if b_ret:
                                    points = BonusPoint.objects.filter(retailer_id=retailer.id, unused_score__gt=0, status=1)
                                    for point in points:
                                        user = get_user_by_openid(point.customer_openid)
                                        user.score += point.unused_score
                                        user.unused_score -= point.unused_score
                                        if user.unused_score < 0:
                                            user.unused_score = 0
                                        user.save(update_fields=["score", "unused_score"])
                                        point.score += F("unused_score")
                                        point.unused_score = 0
                                        point.save(update_fields=["score", "unused_score"])
                    else:
                        user = get_user_by_openid(openid)
                        if user:
                            if user.out_trade_no != out_trade_no:
                                user.out_trade_no = out_trade_no
                                if user.score is None:
                                    user.score = obj.score
                                else:
                                    user.score += obj.score
                                if user.money is None:
                                    user.money = obj.cash_fee
                                else:
                                    user.money += obj.cash_fee
                                user.save(update_fields=["money", "out_trade_no", "score"])
                        else:
                            values = {
                                "openid": openid,
                                "nickname": name,
                                "score": obj.score,
                                "money": obj.cash_fee,
                                "out_trade_no": out_trade_no,
                            }
                            logger.info(values)
                            user = WxUserInfo.objects.create(**values)
                            logging.info(user)

            return HttpResponse(xml)
        except InvalidSignatureException as error:
            logger.info(error)

    # 查询微信订单是否存在
    def query_order(self, transaction_id, out_trade_no):
        wxPay = WeixinPay()
        order_data = wxPay.order.query(transaction_id=transaction_id, out_trade_no=out_trade_no)
        data = dict(order_data)
        if 'return_code' in data and 'result_code' in data and data['return_code'] == 'SUCCESS' and data['result_code'] == 'SUCCESS':
            return True
        else:
            return False


class RechargeStatsAPIView(APIView):
    """商家充值统计"""
    # authentication_classes = ()
    permission_classes = ()

    def get(self, request, *args, **kwargs):
        search_date = request.query_params.getlist("search_date[]", None)

        queryset = RechargeRecord.objects.filter(status=1)

        if search_date and len(search_date):
            queryset = queryset.filter(update_time__date__range=[search_date[0], search_date[1]])

        results = queryset.aggregate(cash_fees=Sum('cash_fee'), scores=Sum('score'))

        return Response(results)
